package pt.um.jspecput.lib.writer;

import static org.junit.Assert.*;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.validation.constraints.Pattern;

import org.databene.benerator.anno.InvocationCount;
import org.databene.feed4junit.Feeder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Feeder.class)
public class MethodWriterHelperTest {

    private static BufferedWriter writer;
    private static BufferedReader reader;
    private static File file = new File("temp");

    @Before
    public void setUp() throws Exception {
        FileHandler.createFile(file);
        writer = new BufferedWriter(new FileWriter(file));
        reader = new BufferedReader(new FileReader(file));
    }

    @After
    public void tearDown() throws Exception {
        reader.close();
        file.delete();
    }

    @Test
    public void testConstructor() {
        MethodWriterHelper mw = new MethodWriterHelper() {
        };

        assertNotNull(mw);
    }

    @Test
    @InvocationCount(10)
    public void testOpenPublicMethodDeclaration_null(
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String expected = "\tpublic " + methodName + "() {";

        MethodWriterHelper.openPublicMethodDeclaration(writer, null,
                methodName, null);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenPublicMethodDeclaration(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String expected = "\tpublic " + type + " " + methodName + "() {";

        MethodWriterHelper.openPublicMethodDeclaration(writer, type,
                methodName, null);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenPrivateMethodDeclaration(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String expected = "\tprivate " + type + " " + methodName + "() {";

        MethodWriterHelper.openPrivateMethodDeclaration(writer, type,
                methodName, null);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenProtectedMethodDeclaration(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String expected = "\tprotected " + type + " " + methodName + "() {";

        MethodWriterHelper.openProtectedMethodDeclaration(writer, type,
                methodName, null);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenNothingMethodDeclaration(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String expected = "\t" + type + " " + methodName + "() {";

        MethodWriterHelper.openNothingMethodDeclaration(writer, type,
                methodName, null);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    public void testCloseMethodDeclaration() throws IOException {
        MethodWriterHelper.closeMethodDeclaration(writer);
        writer.close();

        assertEquals("}", reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenPublicMethodDeclaration_OneArg(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String[] args = { "int a" };
        String expected = "\tpublic " + type + " " + methodName + "(" + args[0]
                + ") {";

        MethodWriterHelper.openPublicMethodDeclaration(writer, type,
                methodName, args);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    @InvocationCount(10)
    public void testOpenPublicMethodDeclaration_TwoArg(
            @Pattern(regexp = "[A-Z][A-Za-z0-9]*") String type,
            @Pattern(regexp = "[a-z][A-Za-z0-9]*") String methodName)
            throws IOException {
        String[] args = { "int a", "int b" };
        String expected = "\tpublic " + type + " " + methodName + "(" + args[0]
                + ", " + args[1] + ") {";

        MethodWriterHelper.openPublicMethodDeclaration(writer, type,
                methodName, args);
        writer.close();

        assertEquals(expected, reader.readLine());
    }

    @Test
    public void testWriteMethodBody_Array() throws IOException {
        String[] lines = { "int c = a+b", "Double d = 0.1;" };

        MethodWriterHelper.writeMethodBody(writer, lines);
        writer.close();

        assertEquals("\t\tint c = a+b;", reader.readLine());
        assertEquals("\t\tDouble d = 0.1;", reader.readLine());
    }

}
